package com.yonyou.pmclouds.plan.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoInsertMultiProcessor;
import com.yonyou.pmclouds.basecom.bp.processor.AuditInfoUpdateProcessor;
import com.yonyou.pmclouds.basecom.bp.template.MultiInsertBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleDeleteBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleUpdateBpTemplate;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.measureindex.entity.MeasureIndexHistoryVO;
import com.yonyou.pmclouds.plan.entity.*;
import com.yonyou.pmclouds.plan.mapper.ScheduleItemMapper;
import com.yonyou.pmclouds.plan.plandriven.rmiitf.IScheduleDriven;
import com.yonyou.pmclouds.plan.planindex.entity.PlanIndexVO;
import com.yonyou.pmclouds.plan.planindex.rmiitf.IPlanIndexMaintain;
import com.yonyou.pmclouds.plan.processor.*;
import com.yonyou.pmclouds.plan.rmiitf.*;
import com.yonyou.pmclouds.plan.utils.ScheduleDataCheckUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * @Description: 计划任务项服务处理类
 * @Author: zhangzhonghao
 * @Date: 2020-03-06
 */

@Service(version = ApplicationConsts.APPLICATION_VERSION, interfaceClass = IScheduleItemService.class)
public class ScheduleItemServiceImpl implements IScheduleItemService {

    @Autowired
    private ScheduleItemMapper scheduleItemMapper;

    @Autowired
    private IScheduleHandleService scheduleHandleService;

    @Autowired
    private IPlanIndexMaintain planIndexMaintain;

    @Autowired
    private ScheduleItemRequiredCheckProcessor requiredCheckProcessor;

    @Autowired
    private ScheduleItemSetParentPlanDateProcessor parentPlanDateProcessor;

    @Autowired
    private ScheduleItemInsertAfterProcessor insertAfterProcessor;

    @Autowired
    private IScheduleItemQueryService itemQueryService;

    @Autowired
    private IScheduleProgressQueryService progressQueryService;

    @Autowired
    private IScheduleProgressService progressService;

    @Autowired
    private IScheduleDriven scheduleDriven;



    @Override
    public ScheduleVO insert(ScheduleVO scheduleVO, ScheduleVO origScheduleVO) throws BusinessException {
        ScheduleItemInsertDefaultValueProcessor defaultValueProcessor = new ScheduleItemInsertDefaultValueProcessor();

        scheduleHandleService.init();

        // 校验必填项
        scheduleHandleService.addIteratorBeforeProcessor(requiredCheckProcessor);

        // 赋默认值
        scheduleHandleService.addIteratorBeforeProcessor(defaultValueProcessor);

        // 根据子级节点推算父级节点时间
        scheduleHandleService.addIteratorAfterProcessor(parentPlanDateProcessor);

        // 迭代处理任务业务逻辑
        scheduleHandleService.handle(scheduleVO, origScheduleVO);

        // 获取需要新增的任务项
        List<ScheduleItemVO> insertItemList = defaultValueProcessor.getInsertScheduleItemList();

        // 设置前置任务关联主键映射
        Map<String, String> codeWithPKMap = defaultValueProcessor.getCodeWithPKMap();
        setDependPlan(insertItemList, codeWithPKMap);

        //这里校验环路及时间
        ScheduleDataCheckUtil.checkData(scheduleVO);

        this.insert(insertItemList.toArray(new ScheduleItemVO[]{}));

        // 保存计划指标
        planIndexMaintain.save(defaultValueProcessor.getInsertScheduleIndexList(), defaultValueProcessor.getDeleteScheduleIndexList());

        return scheduleVO;
    }

    @Override
    public ScheduleItemVO[] insert(ScheduleItemVO[] scheduleItemVOS) throws BusinessException {
        if (scheduleItemVOS == null || scheduleItemVOS.length <= 0) {
            return scheduleItemVOS;
        }

        MultiInsertBpTemplate<ScheduleItemVO> insertBpTemplate = new MultiInsertBpTemplate<>(scheduleItemMapper, false);
        insertBpTemplate.addBeforeProcessor(new AuditInfoInsertMultiProcessor<ScheduleItemVO>());

        return insertBpTemplate.insert(scheduleItemVOS);
    }

    @Override
    public ScheduleVO delete(ScheduleVO scheduleVO) throws BusinessException {
        Map<String, List<ScheduleItemVO>> itemMap = itemQueryService.queryByPkSchedules(new String[]{scheduleVO.getPkSchedule()});
        if(itemMap == null){
            return scheduleVO;
        }

        delete(itemMap.get(scheduleVO.getPkSchedule()).toArray(new ScheduleItemVO[]{}));
        return scheduleVO;
    }

    @Override
    public ScheduleItemVO[] delete(ScheduleItemVO[] scheduleItemVOS) throws BusinessException {
        if (scheduleItemVOS == null || scheduleItemVOS.length <= 0) {
            return scheduleItemVOS;
        }

        SingleDeleteBpTemplate<ScheduleItemVO> deleteBpTemplate = new SingleDeleteBpTemplate<>(scheduleItemMapper);
        deleteBpTemplate.addBeforeProcessor(new AuditInfoUpdateProcessor<ScheduleItemVO>());

        List<String> deletePlanIndexList = new ArrayList<>();
        Set<String> hasPlanIndexSet = new HashSet<>();
        List<String> pkItemList = new ArrayList<>();

        for (ScheduleItemVO itemVO : scheduleItemVOS) {
            pkItemList.add(itemVO.getPkScheduleItem());
            getDeletePlanIndex(hasPlanIndexSet, deletePlanIndexList, itemVO);
            deleteBpTemplate.delete(itemVO);
        }

        if(deletePlanIndexList.size() > 0){
            planIndexMaintain.delete(deletePlanIndexList);
        }

        // 删除对应进度节点
        PlanProgressVO[] progressVOS = progressQueryService.queryByPkItems(pkItemList.toArray(new String[]{}));
        if(progressVOS != null && progressVOS.length > 0){
            progressService.delete(progressVOS);
        }

        return scheduleItemVOS;
    }

    private void getDeletePlanIndex(Set<String> hasPlanIndexSet, List<String> deletePlanIndexList, ScheduleItemVO itemVO){
        if(itemVO.getPlanIndexVOs() != null && itemVO.getPlanIndexVOs().size() > 0){
            for(PlanIndexVO indexVO : itemVO.getPlanIndexVOs()){
                if(hasPlanIndexSet.contains(indexVO.getPkPlanIndex())){
                    continue;
                }
                hasPlanIndexSet.add(indexVO.getPkPlanIndex());
                deletePlanIndexList.add(indexVO.getPkPlanIndex());
            }
        }

        if (itemVO.getChildren() != null && itemVO.getChildren().length > 0) {
            for (ScheduleItemVO childItemVO : itemVO.getChildren()) {
                getDeletePlanIndex(hasPlanIndexSet, deletePlanIndexList, childItemVO);
            }
        }

    }

    @Override
    public ScheduleVO update(ScheduleVO scheduleVO) throws BusinessException {
        // 获取删除的任务项
        ScheduleItemVO[] deleteItemVOS = null;
        if (scheduleVO.getDeletePlan() != null && scheduleVO.getDeletePlan().length > 0) {
            deleteItemVOS = deleteScheduleItemByPks(scheduleVO.getDeletePlan());
        }

        ScheduleItemInsertDefaultValueProcessor defaultValueProcessor = new ScheduleItemInsertDefaultValueProcessor();

        scheduleHandleService.init();

        // 校验必填项
        scheduleHandleService.addIteratorBeforeProcessor(requiredCheckProcessor);

        // 赋默认值
        scheduleHandleService.addIteratorBeforeProcessor(defaultValueProcessor);

        // 推算父级计划时间
        scheduleHandleService.addIteratorAfterProcessor(parentPlanDateProcessor);

        // 迭代处理任务业务逻辑
        scheduleHandleService.handle(scheduleVO, null);

        // 获取新增任务项
        List<ScheduleItemVO> insertItemList = defaultValueProcessor.getInsertScheduleItemList();

        // 获取修改任务项
        List<ScheduleItemVO> updateItemList = defaultValueProcessor.getUpdateScheduleItemList();

        // 设置前置任务主键映射
        Map<String, String> codeWithPKMap = defaultValueProcessor.getCodeWithPKMap();
        setDependPlan(insertItemList, codeWithPKMap);
        setDependPlan(updateItemList, codeWithPKMap);

        this.insert(filterDeleteItem(insertItemList, deleteItemVOS).toArray(new ScheduleItemVO[]{}));
        this.update(filterDeleteItem(updateItemList, deleteItemVOS).toArray(new ScheduleItemVO[]{}));

        // 计划指标修改
        planIndexMaintain.save(defaultValueProcessor.getInsertScheduleIndexList(), defaultValueProcessor.getDeleteScheduleIndexList());

        return scheduleVO;
    }

    /**
     * 删除父级，同时也删除子级，过滤掉已经被删除的数据
     * @param itemVOList 任务项
     * @param deleteItemVOS 已删除任务项
     */
    private List<ScheduleItemVO> filterDeleteItem(List<ScheduleItemVO> itemVOList, ScheduleItemVO[] deleteItemVOS){
        if(deleteItemVOS == null || deleteItemVOS.length <= 0){
            return itemVOList;
        }
        List<ScheduleItemVO> newItemVOList = new ArrayList<>();
        Map<String, ScheduleItemVO> deleteItemMap = new HashMap<>();
        for(ScheduleItemVO itemVO : deleteItemVOS){
            deleteItemMap.put(itemVO.getPkScheduleItem(), itemVO);
        }

        for(ScheduleItemVO itemVO : itemVOList){
            if(deleteItemMap.get(itemVO.getPkScheduleItem()) == null){
                newItemVOList.add(itemVO);
            }
        }

        return newItemVOList;

    }

    private ScheduleItemVO[] deleteScheduleItemByPks(String[] pkItems) throws BusinessException {
        List<ScheduleItemVO> itemVOS = itemQueryService.queryByPkItems(pkItems);
        if (itemVOS == null || itemVOS.size() <= 0) {
            return null;
        }

        List<ScheduleItemVO> deleteItemVOS = new ArrayList<>();
        // 去除判断，因为可能父级与子级主键均存在了删除字段上
        Set<String> hasDeletePkItemSet = new HashSet<>();
        for (ScheduleItemVO itemVO : itemVOS) {
            getDeleteItemVO(deleteItemVOS, hasDeletePkItemSet, itemVO);
        }

        return this.delete(deleteItemVOS.toArray(new ScheduleItemVO[]{}));

    }

    private void getDeleteItemVO(List<ScheduleItemVO> deleteItemVOS, Set<String> hasDeletePkItemSet, ScheduleItemVO itemVO){
        if(!hasDeletePkItemSet.contains(itemVO.getPkScheduleItem())){
            deleteItemVOS.add(itemVO);
            hasDeletePkItemSet.add(itemVO.getPkScheduleItem());
        }

        if (itemVO.getChildren() != null && itemVO.getChildren().length > 0) {
            for (ScheduleItemVO childItemVO : itemVO.getChildren()) {
                getDeleteItemVO(deleteItemVOS, hasDeletePkItemSet, childItemVO);
            }
        }
    }

    @Override
    public ScheduleItemVO[] update(ScheduleItemVO[] scheduleItemVOS) throws BusinessException {
        if (scheduleItemVOS == null || scheduleItemVOS.length <= 0) {
            return scheduleItemVOS;
        }

        SingleUpdateBpTemplate<ScheduleItemVO> updateBpTemplate = new SingleUpdateBpTemplate<>(scheduleItemMapper,
                ScheduleItemVO.UPDATE_FIELDS);
        updateBpTemplate.addBeforeProcessor(new AuditInfoUpdateProcessor<ScheduleItemVO>());
        for (ScheduleItemVO itemVO : scheduleItemVOS) {
            updateBpTemplate.update(itemVO);
        }

        return scheduleItemVOS;
    }

    private void setDependPlan(List<ScheduleItemVO> itemVOList, Map<String, String> codeWithPKMap) throws BusinessException {
        if (itemVOList != null) {
            for (ScheduleItemVO itemVO : itemVOList) {
                if(StringUtils.isNotEmpty(itemVO.getDependPlanName())) {
                    itemVO.setDependPlan(codeWithPKMap.get(itemVO.getDependPlanName()));
                }
            }
        }
    }

    @Override
    public ScheduleReportVO updateProgress(ScheduleReportVO reportVO) throws BusinessException {
        if(reportVO == null){
            return null;
        }

        // 更新计划指标
        updateScheduleIndex(reportVO);

        // 更新进度
        progressService.updateProgress(reportVO);

        // 计划驱动
        drivePlan(reportVO);
        return reportVO;

    }


    private void drivePlan(ScheduleReportVO reportVO) throws BusinessException {
        PlanProgressVO progressVO = reportVO.getPlanProgressVO();

        if(progressVO.getProgress() != PlanProgressVO.SCHEDULE_ITEM_COMPLETE){
            return;
        }

        List<ScheduleItemVO> itemList = itemQueryService.queryByPkItems(new String[]{reportVO.getPkScheduleItem()});
        if (itemList == null || itemList.size() <= 0)
            return;

        List<ScheduleItemVO> planDrivenList = new ArrayList<>();
        for (ScheduleItemVO itemVO : itemList) {
            // 关联单据的计划、已完成的计划不驱动
            if(StringUtils.isNotEmpty(itemVO.getRelatedBillType()) || Objects.equals(itemVO.getCompletedStatus(), PlanProgressStatusConst.PLAN_COMPLETED)){
                return;
            }

            itemVO.setPlanFinisher(StringUtils.isEmpty(progressVO.getModifier()) ? progressVO.getCreator() : progressVO.getModifier());
            planDrivenList.add(itemVO);
        }
        // 驱动计划
        scheduleDriven.drivePlansByProgress(planDrivenList.toArray(new ScheduleItemVO[0]));
    }

    private void updateScheduleIndex(ScheduleReportVO reportVO) throws BusinessException{
        if(reportVO.getIndexHistoryVOS() == null || reportVO.getIndexHistoryVOS().length <= 0){
            return;
        }

        // 更新指标
        MeasureIndexHistoryVO[] indexHistoryVOS = reportVO.getIndexHistoryVOS();

        // 如果新增了指标，更新任务的指标个数
        List<ScheduleItemVO> itemList = itemQueryService.queryByPkItems(new String[]{reportVO.getPkScheduleItem()});

        if(itemList != null && itemList.size() > 0){
            ScheduleItemVO itemVO = itemList.get(0);
            if(itemVO.getIndexNumber() != indexHistoryVOS.length){
                itemVO.setIndexNumber(indexHistoryVOS.length);
                this.update(new ScheduleItemVO[]{itemVO});
            }
        }

        List<PlanIndexVO> insertPlanIndexList = new ArrayList<>();
        for(MeasureIndexHistoryVO historyVO : indexHistoryVOS){
            if(historyVO.getPkPlanIndex() == null){
                PlanIndexVO planIndexVO = new PlanIndexVO();

                planIndexVO.setPkProject(reportVO.getPkProject());
                planIndexVO.setPkMeasureIndex(historyVO.getPkMeasureindex());
                planIndexVO.setPkPlan(reportVO.getPkScheduleItem());
                planIndexVO.setPkPlanIndex(UUID.randomUUID().toString());
                planIndexVO.setExpectTotal(historyVO.getExpectTotal());
                insertPlanIndexList.add(planIndexVO);

                historyVO.setPkPlanIndex(planIndexVO.getPkPlanIndex());
            }
        }

        if(insertPlanIndexList.size() > 0){
            planIndexMaintain.insert(insertPlanIndexList.toArray(new PlanIndexVO[]{}), false);
        }

    }

    @Override
    public ScheduleVO updateForAdjust(ScheduleVO scheduleVO, ScheduleVO origScheduleVO) throws BusinessException {
        ScheduleItemAdjustDefaultValueProcessor defaultValueProcessor = new ScheduleItemAdjustDefaultValueProcessor();

        scheduleHandleService.init();

        // 校验必填项
        scheduleHandleService.addIteratorBeforeProcessor(requiredCheckProcessor);

        // 赋默认值
        scheduleHandleService.addIteratorBeforeProcessor(defaultValueProcessor);

        // 根据子级节点推算父级节点时间
        scheduleHandleService.addIteratorAfterProcessor(parentPlanDateProcessor);

        // 迭代处理任务业务逻辑
        scheduleHandleService.handle(scheduleVO, origScheduleVO);

        // 获取需要新增的任务项
        List<ScheduleItemVO> insertItemList = defaultValueProcessor.getInsertScheduleItemList();

        // 设置前置任务关联主键映射
        Map<String, String> codeWithPKMap = defaultValueProcessor.getCodeWithPKMap();
        setDependPlan(insertItemList, codeWithPKMap);

        this.insert(insertItemList.toArray(new ScheduleItemVO[]{}));

        // 复制上一版本填报的进度
        Map<String, String> oldPkWithNewMap = defaultValueProcessor.getOldPkWithNewMap();
        copyLastVersionProgress(oldPkWithNewMap);

        // 保存计划指标
        planIndexMaintain.save(defaultValueProcessor.getInsertScheduleIndexList(), null);

        return scheduleVO;
    }

    private void copyLastVersionProgress(Map<String, String> oldPkWithNewMap) throws BusinessException {
        List<String> oldItemPkList = new ArrayList<>();
        for(Map.Entry<String, String> entry : oldPkWithNewMap.entrySet()){
            oldItemPkList.add(entry.getKey());
        }

        PlanProgressVO[] planProgressVOS = progressQueryService.queryByPkItems(oldItemPkList.toArray(new String[]{}));

        if(planProgressVOS == null || planProgressVOS.length <= 0){
            return;
        }

        List<PlanProgressVO> insertProgressList = new ArrayList<>(planProgressVOS.length);

        for(PlanProgressVO progressVO : planProgressVOS){
            progressVO.setPkPlan(oldPkWithNewMap.get(progressVO.getPkPlan()));
            insertProgressList.add(progressVO);
        }

        progressService.insert(insertProgressList.toArray(new PlanProgressVO[]{}));

    }
}
